/*
	UIObjectPtr.h
*/

#pragma once
#include <assert.h>
#include <type_traits> 

namespace DirectUI
{
	template<typename T>
	class CUIObjectPtr
	{
	public:

		CUIObjectPtr(T* lp = NULL) : p(lp)
		{
			//assert((std::tr1::is_base_of<IUIObject, T>::value));
			if (p)
			{
				p->AddRef();
			}
		}

		CUIObjectPtr(const CUIObjectPtr<T>& lp)
		{
			//assert((std::tr1::is_base_of<IUIObject, T>::value));
			p = lp.p;

			if (p)
			{
				p->AddRef();
			}
		}

		T* operator=(T* lp)
		{
			if (p)
			{
				p->Release();
			}

			p = lp;

			if (p)
			{
				p->AddRef();
			}

			return p;
		}

		T* operator=(const CUIObjectPtr<T>& lp)
		{
			if (p)
			{
				p->Release();
			}

			p = lp.p;

			if (p)
			{
				p->AddRef();
			}

			return p;
		}

		~CUIObjectPtr()
		{
			if (p)
			{
				p->Release();
				p = NULL;
			}
		}

		operator T*() const
		{
			return p;
		}

		T& operator*() const
		{
			return *p;
		}

		T** operator&()
		{
			//The assert on operator& usually indicates a bug. Could be a potential memory leak.
			// If this really what is needed, however, use GetInterface() explicitly.
			assert(NULL == p);
			return &p;
		}

		T* operator->() const
		{
			return p;
		}

		bool operator!() const
		{    
			return (NULL == p);
		}

		bool operator<(T* lp) const
		{
			return p < lp;
		}

		bool operator!=(T* lp) const
		{
			return !operator==(lp);
		}

		bool operator==(T* lp) const
		{
			return p == lp;
		}

	protected:
		T* p;
	};

	template <class T, const IID* piid = &__uuidof(T)>
	class CUIObjectQIPtr : public CUIObjectPtr<T>
	{
	public:
		CUIObjectQIPtr()
		{

		}

		CUIObjectQIPtr(_In_opt_ IUIObject* lp)
		{
			if ( lp != NULL )
				lp->QueryInterface(*piid, (void **)&p);
		}
	};
};